# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: leon

import datetime
import functools
import typing

from coin.exchange.base.kr_rest.futures_product import (NativeFuturesProduct,
                                                        NormFuturesProduct,
                                                        parse_futures_product_symbol)
import coin.exchange.deribit_v1.kr_rest.contract_util as contract_util
from coin.exchange.deribit_v1.kr_rest.currency import DeribitCurrency
from coin.exchange.deribit_v1.kr_rest.futures_constants import (base_currency_list)


class DeribitFuturesProduct(NativeFuturesProduct):
  _exchange = 'Deribit'
  NativeCurrencyType = DeribitCurrency

  def __init__(self,
               base: DeribitCurrency,
               quote: DeribitCurrency,
               expiry: typing.Union[datetime.datetime, datetime.date, str],
               contract_type: str):
    assert quote.currency == 'USD', 'Only USD is supported as quote.'

    native_expiry_str = contract_util.to_native_expiry_str(expiry, contract_type)
    native_symbol = '%s-%s' % (base.native_currency, native_expiry_str)

    super().__init__(base=base, quote=quote, expiry=expiry, native_symbol=native_symbol)
    self._contract_type = contract_type

  def __repr__(self):
    return str(super().__repr__(self.contract_type))

  @property
  def contract_type(self):
    return self._contract_type

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromProductImpl(cls, product, current_datetime):
    assert isinstance(product, NormFuturesProduct), type(product)
    assert product.quote.currency == "USD"
    contract_type = contract_util.find_contract_type_from_expiry(current_datetime, product.expiry)
    return cls(product.base, product.quote, product.expiry, contract_type)

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromStrProductImpl(cls, product, current_datetime):
    assert isinstance(product, str), product

    parsed_result = parse_futures_product_symbol(product)
    assert parsed_result['base'] in base_currency_list, parsed_result['base']
    assert parsed_result['quote'] == 'USD', parsed_result['quote']
    expiry_str = parsed_result['expiry'].lower()
    expiry, contract_type = contract_util.to_expiry_contract_type(expiry_str, current_datetime)

    base = cls.NativeCurrencyType.FromStrCurrency(parsed_result['base'])
    quote = cls.NativeCurrencyType.FromStrCurrency('USD')
    return cls(base, quote, expiry, contract_type)

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromStrNativeProductImpl(cls, product, current_datetime):
    assert isinstance(product, str), product

    # Native symbol string.
    base, expiry_str = product.split('-')
    assert base in base_currency_list
    expiry, contract_type = contract_util.parse_native_expiry_contract_type(
        expiry_str, current_datetime)

    base = cls.NativeCurrencyType.FromStrNativeCurrency(base)
    quote = cls.NativeCurrencyType.FromStrNativeCurrency('USD')
    return cls(base, quote, expiry, contract_type)

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromCurrencyPair2AndContractTypeImpl(cls, base, quote, contract_type, current_datetime):
    expiry = contract_util.find_expiry_from_contract_type(current_datetime, contract_type)
    assert quote.currency == 'USD'
    return cls(base, quote, expiry, contract_type)
